home *** CD-ROM | disk | FTP | other *** search
- -----BEGIN PGP SIGNED MESSAGE-----
-
- require 5.000;
-
- # PerlVision - A class library to do ANSI graphics and textmode GUI
- # By Ashish Gulhati (hash@well.sf.ca.us)
- # V.0.1.0
- #
- # (C) Ashish Gulhati, 1995. All Rights Reserved.
- #
- # Free electronic distribution permitted. You are free to use
- # PerlVision in your own code so long as this copyright message stays
- # intact. PerlVision or derived code may not be used in any commercial
- # product without my prior written or PGP-signed consent. Please e-mail
- # me if you make significant changes, or just want to let me know what
- # you're using PerlVision for.
-
-
- INTRO
- =====
-
- I needed a basic text-mode GUI framework to implement some
- nice-looking proggies on Linux. Didn't find any around, so necessity
- became the mother of PerlVision. And this beast kept growing as I made
- love to Perl, so now it's far from 'basic'. Provides 90% of the
- features you'd want for a user interface, including checkboxes,
- radiobuttons, three different styles (!) of pushbuttons, single and
- multiple selection listboxes, an extensible editbox that does
- autowrapping, a scrollable viewbox, single line text entry fields, a
- menubar with pulldown menus, and full popup dialog boxes with multiple
- controls, as well as optimization of screen updates to minimize
- transmission overhead on slow modem lines.
-
- PerlVision is much more powerful and pretty than dialog, if I do say
- so myself. It is probably somewhat Linux specific, I haven't tried it
- on any other system, and it needs work to speed it up, which I'll get
- around to soon.
-
- PerlVision will only work with Perl 5+ of-course (upgrade || die()!).
-
-
- MANIFEST
- ========
-
- The perlvision.tgz file should contain:
-
- pvbasic.pl - Basic primitives for ANSI screen control, etc.
- pvbasic_u.pl - 'Unoptimized' pvbasic.pl (faster on console)
- perlvision.pl - The class library
- perlvision.doc - This file
- rap - (rap ain't pico) A simple text editor as an example
- of using PerlVision.
- COPYING - The GPL - terms and conditions under which rap (but
- not the rest of PerlVision) is distributed
- README - General description of how to get started
- IAFA-PACKAGE - The IETF FTP Archives Working Group standard format
- description of PerlVision.
-
- PerlVision is not public domain or copylefted software. You may make
- use of it for free as long as the resulting programs are not to be
- used for any commercial purpose. _Any_ commercial use of PerlVision
- requires my prior consent. If you aren't sure whether a certain use is
- 'commercial' on 'non-commercial', assume it is commercial and mail me.
-
-
- BASICS
- ======
-
- Programs that use PerlVision should call pv::initvision() before doing
- any screen manipulation or creating any PerlVision objects. Before
- exiting, programs should call pv::exitvision() to set the terminal
- back to normal. pv::initvision() can be called with an argument that
- tells it whether or not to use IBM-PC high bit characters.
-
- pv::initvision(1) sets it up to use high bit line drawing characters
- pv::initvision(0) sets it up to use makeshift 7 bit characters.
-
- All proggies that use PerlVision should use the pv::pvprint() function
- instead of the standard print operator for terminal I/O, and use the
- attribute/cursor manipulation functions in pvbasic.pl rather than send
- the codes directly. This enables PerlVision to:
-
- 1. keep track of the contents of the screen so that trashed screens
- can be restored and transient popup windows can restore what was under
- them when they vanish, and
-
- 2. provide some amount of curses style optimization when updating the
- screen. While this optimization is currently rather inefficient and
- actually _slows_ the display on a terminal connected with a fast link
- (like the console), it does accomplish its primary function which is
- to keep the number of characters transmitted to a minimum for the
- benefit of folks using the proggy over a slow terminal line, like over
- a modem.
-
- pv::pvprint() is behaves almost identically to print() except it don't
- like multiple line input (it'll strip everything after the first
- newline), and it don't like you to use terminal control escape codes
- (it won't complain about this, but you'll be defeating the whole
- purpose if you do it).
-
- So to flush the virtual screen built up by the use of pvprint() calls,
- you use pv::refresh(); There's also a pv::redraw() to completely
- redraw the whole screen (useful if screen is trashed - I normally have
- all the controls do this if they receive a ^L keystroke).
-
- Finally, pv::standard sets up a standard screen for you to use. I
- wrote PerlVision to serve as an interface for a much larger project,
- and that's what I wanted all my screens to look like, so that's what's
- standard. If you decide to go with a different look, the controls
- should still work just fine, but since colors are hardcoded
- everywhere, it might look funny without a cyan background. Ideally
- somebody will hack around and fix up PerlVision to use a color table
- for attributes of all the controls, but it ain't gonna be me. ;)
-
- The same goes with keystrokes. Package pv has a function called
- getkey() which is used for most keyboard input as it does some
- interpretation before submitting the result. I use emacs-like meta
- sequences for things like Help and Main Menu activation, so M-h and
- M-x are defined for that and will exit any control that has focus. If
- you want to change that, well, you have the source.
-
- Look in pvbasic.pl or in the source for rap to see what functions to
- use to set cursor position, colors, etc. It's all mostly
- self-explanatory. Any function that uses terminal capabilities that
- give it extra speed (cls, cleol, hardware scrolling) DON'T wait for a
- refresh() call, but so their deeds right away. That's because
- refresh() isn't smart enough to optimize to that great an extent, and
- it would be horrid to have it put out 24x80 chars everytime you did a
- cls(). These functions still do update the internally stored status of
- the screen, of-course.
-
-
- CLASSES
- =======
-
- The following object classes are defined:
-
- PV_Static (A static text region, trivial class)
- PV_Checkbox (A single 2-state checkbox)
- PV_Radio (A single 2-state radiobutton)
- PV_RadioG (A group of connected radiobuttons)
- PV_Listbox (A single selection list box)
- PV_Mlistbox (A multiple selection list box)
- PV_Entryfield (A single line text entry field)
- PV_Password (A single line text entry field that *'s out what's typed)
- PV_Menubar (A top line menu bar with single-level pulldown submenus)
- PV_Combobox (A combo box)
- PV_Editbox (A multi line edit box)
- PV_Viewbox (A readonly viewer/pager for text files)
- PV_Pushbutton (A push button that takes 3 lines of screen real estate)
- PV_Cutebutton (A push button that takes 2 lines of screen real estate)
- PV_Plainbutton (A no-frills button that fits on a single line)
- PV_Dialog (A full dialog box with as many controls as you like)
-
- * Other classes are defined for internal use by PerlVision and should
- not be used from outside. Also, see below why use of the PV_Radio
- control is limited from outside.
-
- * Constructors for all the classes are called new().
-
- * All classes expect that you will not fiddle with the object's data
- yourself.
-
- * All nontrivial controls (except PV_RadioG, see below) have an
- activate() method. It makes the control active, and returns when any
- traditional shift focus key is pressed - see the section on
- PV_Dialog for more details.
-
- * All nontrivial controls have a stat() method, which returns the
- status of the control (checked, unchecked, text, whatever).
-
-
- I. PV_Static
- ============
-
- $foo = new PV_Static ("Text",$x1,$y1,$x2,$y2);
-
- This is the trivial text region control. It's there mainly so you can
- put static text in dialog boxes. It don't have a activate() or stat()
- method.
-
- $foo->display;
-
- to display the text. If your text doesn't fit in the space you
- allocate, it'll be truncated. It's also your responsibility to provide
- line breaks if you don't want all the text to be thought of as a
- single line.
-
-
- II. PV_Checkbox
- ===============
-
- $foo = new PV_Checkbox ("Label",$x,$y,$stat);
-
- $x,$y are the X and Y co-ordinates to place the control.
- $stat is 1 if the Checkbox is checked, 0 if not. You can pre-initialize.
- "Label" is printed on the left of the checkbox.
-
- $foo->display; Displays checkbox.
- $foo->activate; Gives it focus. Exits on 1,2,3,4,5,6,7 codes.
- $foo->select; Toggles status.
- $foo->stat; Returns status. (1 checked, 0 unchecked)
-
-
- III. PV_Radio
- =============
-
- $foo = new PV_Radio ("Label",$x,$y,$stat);
-
- PV_Radio is a direct descendant of PV_Checkbox that just looks a bit
- different. All the methods defined for PV_Checkbox are defined for
- PV_Radio as well, BUT don't try to use PV_Radio as a different looking
- PV_Checkbox.
-
- Because radio buttons are generally meant to be grouped and to affect
- the state of all other buttons in the group. So unless you include a
- radio button in a group with PV_RadioG (see below), you're liable to
- hurt something. Once it's in a group you can use all the methods
- outlined above for PV_Checkbox.
-
-
- IV. PV_RadioG
- =============
-
- $foo = new PV_RadioG ($radio_1,$radio_2,$radio_3...);
-
- $radio_* are PV_Radio objects.
-
- See? You take your PV_Radio objects, and feed them to the constructor
- for PV_RadioG, and out pops a radio button group.
-
- Now you can use:
-
- $foo->display; Displays all radio buttons in group.
- $foo->stat; To figure out which button is the one that's
- selected. This returns the Label of the selected
- button.
-
- PV_RadioG has no 'activate' method. You activate the PV_Radio objects
- directly. This is much more flexible for use in dialog boxes.
-
-
- V. PV_Listbox
- =============
-
- $foo = new PV_Listbox ("Head",$x1,$y1,$x2,$y2,"Label1",0,"Label2",0...);
-
- Yes, the element following each "Labeln" should be 0 for this to work
- right.
-
- "Label*" are the strings that will be shown in the listbox. "Head"
- will be printed across above the top of the listbox.
-
- $foo->activate; Gives it focus. Exits on 5,6,7,8 exit codes.
- $foo->stat; Returns the label of the selected entry.
-
-
- VI. PV_Mlistbox
- ===============
-
- $foo = new PV_Mlistbox ("Head",$x1,$y1,$x2,$y2,"Label1",0,"Label2",0...);
-
- Yes, the element following each "Labeln" should be 0 for this to work
- right.
-
- "Label*" are the strings that will be shown in the listbox. "Head"
- will be printed across above the top of the listbox.
-
- $foo->activate; Gives it focus. Exits on 5,6,7,8 exit codes.
- $foo->stat; Returns a list of all selected labels.
-
-
- VII. PV_Entryfield
- ==================
-
- $foo = new PV_Entryfield ($x,$y,$length,$max,"Label","Initial Value");
-
- $length is the length of the text entry area.
- $max is the maximum length of the input. actually this is ignored. ;-)
- "Label" is printed to the left of the entry field. Can be "".
- The entryfield is pre-initialized to "Initial Value". Can be "".
-
- $foo->activate; Gives it focus. Exits on 1,2,5,6,7,8 exit codes.
- Changed text is always saved, regardless of
- how the loop exited.
- $foo->stat; Returns the text value of the entryfield.
-
-
- VIII. PV_Password
- =================
-
- Identical to PV_Entryfield except that it displays '*'s instead of
- what the user types.
-
-
- IX. PV_Menubar
- ==============
-
- The menu bar is a bit odd. The way you do it is set it up with just
- one pulldown, then add pulldowns to it till you have enough. Don't add
- too many (i.e. that there's not enough space for their heads on the
- menubar) or things will definitely get broken.
-
- $foo = new PV_Menubar ("Head",$width,$depth,"label1",0,"label2",0...);
-
- Just like with the listboxes, each list element is followed by a
- 0. This list becomes your first pulldown. Now to add more pulldowns, do:
-
- $foo->add("Head",$width,$depth,"label1",0,"label2",0...);
-
- That's the second pulldown, and so on.
-
- Because of this step by step method of building up the menubar, you
- need to display it once you're finished adding pulldowns, it doesn't
- automatically display itself. Do a:
-
- $foo->display();
-
- To activate:
-
- $foo->activate();
-
- It'll exit on 5, 7, and 8. On 8, it'll give you a second element in
- the return list of the form "Pulldown:Selection". The "Pulldown" is
- the head of the pulldown menu, the "Selection" is the label of the
- selection.
-
- Help context does not come through on the 5 exit code. i.e. you can't
- tell which pulldown was active when help was requested, or which
- selection in which pulldown. C'est la vie.
-
-
- X. PV_Combobox
- ==============
-
- Not implemented yet. I'll get around to it. Actually it's a pretty
- trivial offspring of a listbox and an entryfield.
-
-
- XII. PV_Editbox
- ===============
-
- $foo = new PV_Editbox ($x1,$y1,$x2,$y2,$margin,"Text",$index,$start);
-
- $margin is the word-wrap boundary. If it's bigger than the size of the
- box, that's your headache.
-
- $text is a text string to be dumped into the editbox. it will be
- stripped of CRs (not LFs), TABs, and nulls, and justified the way the
- editbox does it (see below).
-
- $index is the start position within the text to initially place the
- cursor at. First char is 0.
-
- $start is the line number to position at the top of the editbox, if
- possible. First line is 0.
-
- $foo->activate; Gives it focus. Exits on 5,6,7 exit codes.
- Changed text is always saved, regardless of
- how the loop exited.
- $foo->stat; Returns the text value of the editbox.
-
- There are some hooks in there to let you subclass it and do
- things. One is an empty 'sub statusbar' that's called every-time the
- display is refreshed. Another is an empty 'sub process_key' which is
- used extensively in rap to build a full editor out of the editbox
- control.
-
- The editbox does automatic word-wrapping and reverse word-wrapping and
- other fancy stuff. The style of auto-wrapping I chose is what
- personally irritates me the least (all auto-wraps irritate me). Trying
- to change the wrap style is likely to be very hairy, and will prolly
- break the editbox. It took a lot of tweaking of plenty of regexps to
- get it to work the way it does.
-
- The editbox used to scale quite poorly with increasing text sizes
- initially, but I've cleaned it up so there's only one or two places
- where the size of the input text matters at all to the
- speed. Basically it should now be more or less constant efficiency
- most of the time, except when an auto-wrap occurs, at which time, the
- size of the text makes a significant difference. I'll make that
- size-independent as well in the next version.
-
-
- XIII. PV_Viewbox
- ================
-
- $foo = new PV_Viewbox ($x1,$y1,$x2,$y2,$text,$start);
-
- Much like PV_Editbox but it's readonly and the arrow keys have
- different bindings. I will eventually implement hardware scrolling in
- viewboxes that extend the length of the display so that it's a fast
- browser.
-
-
- XIV. PV_Pushbutton, PV_Cutebutton, PV_Plainbutton
- =================================================
-
- $foo = new PV_Pushbutton ("Label",$x1,$y1);
-
- Makes a simple push button.
-
- $foo->display(); displays it.
-
- $foo->activate(); activates it.
-
- Exits on codes 1,2,3,4,5,6,7,8. On 8, it 'depresses' and it's up to
- you to 'undepress' it by calling the display method.
-
- PV_Pushbutton is BIG. It takes 3 lines on the screen. PV_Cutebutton is
- my favorite - it takes only two lines, and actually pushes and pops
- around so it's fun to watch ;) PV_Plainbutton is a basic one-line
- button which does absolutely nothing fancy but is very useful in some
- situations (e.g. for hyper-text).
-
-
- XV. PV_Dialog
- =============
-
- This is the guy that puts it all together and does all the work of
- managing how focus switches between multiple controls in a dialog
- box. Once you've created all the controls you need, you can feed them
- to PV_Dialog and out pops an object that you can trust to handle
- everything. Above you would have noticed that the activate loops for
- all controls return en exit code when focus is released. This is what
- these codes mean:
-
- When an activate loop exits, it returns a code telling you the reason
- for exiting:
-
- 1 = Up Arrow (Traditional shift-focus key)
- 2 = Down Arrow (Traditional shift-focus key)
- 3 = Right Arrow (Traditional shift-focus key)
- 4 = Left Arrow (Traditional shift-focus key)
- 5 = M-h (For help)
- 6 = M-x (For menu)
- 7 = Tab (Traditional shift-focus key)
- 8 = Enter (Traditional 'Done here' key)
-
- These codes are used by the PV_Dialog control to figure out how to
- switch focus between controls, and when to exit. Here's how to create
- a PV_Dialog object:
-
- $foo = new PV_Dialog ("Title",$x1,$y1,$x2,$y2,$style,$color,
- $control1,1,2,2,1,1,1,2,0,
- $control2,1,3,3,1,2,2,3,0,
- ...);
-
- "Title" is currently ignored.
- $style: if 1, creates a popup that is 'raised'.
- if 0, creates a popup that is 'depressed'
- $color is the background color for the dialog. I'd recommend 6 (cyan)
- because of the overall hardcoded buddha-nature of colors at
- present.
-
- $control* are PV_* objects that you created beforehand (I think they
- can even be PV_Dialog types, though I haven't tested it. They can't be
- PV_Menubar types of-course).
-
- How this works is that the matrix tells PV_Dialog which control to
- switch focus to on each og the 8 exit codes listed above. So when you
- do a:
-
- $foo->activate;
-
- PV_Dialog starts off by displaying itself and giving focus to
- $control1. When $control1 exits, $foo looks in the list that follows
- $control1 in the constructor syntax above to figure out which control
- to give focus to next. The list is simply numbers that say which
- control. So 1 represents $control1, 2 represents $control2, and so on,
- strictly based on the order in which the controls appear in the
- constructor invocation.
-
- The special value 0 is reserved to tell PV_Dialog that it's time to
- exit and hide the dialog box. I also use it as a place-holder for
- those exit-codes that a certain control never returns, for example of
- $control1 above was a PV_Editbox, I'd put 0's in the list following
- $control1 at positions 1,2,3 and 4 because the edit box object never
- exits on those codes (those keys have meaning within the editbox)
-
- If you don't want focus to switch off a control when a certain
- exitcode is returned, simply put that control's own number in the
- corresponding position in the list.
-
- Look in the rap code for an example of PV_Dialog use, the $options
- object. It's generally very easy and powerful.
-
- When PV_Dialog's activate exits, it returns a two-element list. First
- element tells you which was the last control to be active (again
- numbered as they appear in the constructor invocation), and the second
- element tells you what exitcode that control returned.
-
- After the dialog box has exited, you can call 'stat' on each control
- to find out what's up. Remember, don't put PV_RadioG controls in a
- dialog box, they don't have an activate method. Put the corresponding
- PV_Radio controls in. When you 'stat', you'll be 'stat'ing the
- PV_RadioG.
-
- Also, don't ever put a PV_Static as the first control in a
- PV_Dialog. It doesn't have an activate method. If you just want a
- pop-up box with text and no other controls, either consider using a
- PV_Viewbox control, or write the text onto the popup box yourself with
- pv::pvprint.
-
-
- More goodies: PVD
- =================
-
- PerlVision also defines two often needed dialog box styles:
-
- PVD::message (A simple message box with OK button)
- PVD::yesno (An option box with Yes/No buttons)
-
- Both self-center, and make sure the box is big enough to hold the
- buttons. They don't bother to check if the screen will hold the dialog
- box, or the dialog box will hold your text. Both use the following
- syntax:
-
- PVD::message ("Text",width,depth);
-
- PVD::yesno returns 1 for yes and 0 for no.
-
- Width and depth are how big you want the text part of the box to be
- (the buttons are separate).
-
-
- BUGS
- ====
-
- * ORA don't have a distributor in India, so I don't own a camel.
- * $max in PV_Entryfield is a misnomer. It's actually used internally
- and should be set to 0 when you create a new entryfield object.
- * Colors are hardcoded.
- * Terminal control sequences are hardcoded.
- * Keystroke sequences are hardcoded.
- * No support for multiple overlapping 'windows'.
- * The virtual screen 'optimization' code could do with a few orders of
- magnitude increase in performance. I'll rewrite it as a C module
- when I figure out how that's done. Or using ncurses if I figure out
- how to access ncurses from Perl. Assistance welcome.
- * Why do people use text mode if they want GUI controls?
-
-
- CRUFTS
- ======
-
- * I've included pvbasic_u.pl with the distribution for now. This is
- basically an old version of the pvbasic.pl _without_ the
- screen-optimization code, hacked up with the new version in places so
- that it does at least keep a track on the status of the screen
- (without which PerlVision's transient window support would break). The
- idea is that until I get around to coding the screen optimization code
- in C, folks can use pvbasic_u.pl on fast terminals. It's substantially
- faster on console than the real pvbasic.pl. Hopefully I'll soon have
- an ncurses-based pvbasic.pl done, which will be much faster than
- either of these two.
-
-
- TO DO
- =====
-
- * PV_Combobox
- * Hardware scrolling for listboxes, viewboxes and editboxes that
- extend the width of the screen.
- * Speed up screen optimization
- * Make screen updating 'interruptible' so that if you know what you're
- doing, you needn't wait till the update is done - much like the
- 'type-ahead' mode in BBS packages. Suggestions on how to implement
- this are welcome.
- * Implement hot-keys in menubar and pulldowns.
- * Use termcap || terminfo for terminal characteristics. Preferably
- ncurses as that'll take care of the screen optimization problem as well.
- * Make listboxes more extensible
- * Add quoting support to editbox's justify routine
- * Make syntax identical to Tk eventually, so the same code can be made
- X capable with a minimum of fuss.
- * Make auto-fill optional in editbox and fix tab handling so that rap
- can also be used to edit /etc/hosts instead of just mail ;-/
- * Implement keymap objects. pv::getkey is just an excuse for an input
- model.
-
- IF YOU KNOW OF A WORKING XS INTERFACE FOR LINKING PERL WITH NCURSES,
- or have the skills and the time to help make it, please e-mail me. All
- other offers of help with future versions of PerlVision, suggestions
- for improvement, as well as news on what you're using PerlVision for
- are welcome.
-
- Enjoy!
-
-
- THANKS TO
- =========
-
- Raj, my Unix mentor. Kishore for being such a nice guy and blunt
- freak. Anindo for suggestions, cigarettes, and hair-raising bike
- rides. Steve for encouragement and eats. Uma for not distracting me
- with her lovely kisses for a while. Atul, Rishab and Pawan for
- existing. Mohua for company. Emily Saliers and Neil Peart for
- fantastic music. Larry Wall for Perl. RMS for Emacs.
-
-
- ============================================================================
- __
- -----==- / /\ Ashish Guhati
- ----==-- _ / / \ hash@netropolis.com
- ---==---(_)__ __ ____ __ / / /\ \ hash@well.sf.ca.us
- --==---/ / _ \/ // /\ \/ / / /_/\ \ \ Vox: +91 11 4615433
- -=====/_/_//_/\_,_/ /_/\_\ /______\ \ \ BBS/FAX: +91 11 4601978
- The choice of a GNU generation \_________\/ http://c2.org/~hash/
-
- Finger hash@well.sf.ca.us for PGP public key.
- ============================================================================
-
- -----BEGIN PGP SIGNATURE-----
- Version: 2.6.2
-
- iQCVAwUBL3CUWGXU8SuBC/ZVAQG4GAQAgjSD1zZdmdFUsOzjJ2xTSEAmmknBemb9
- uKZ+LET7gPm6gZ3xPQrOqGKz2Lp8uvOjDd0hMSAZYP4nZDG5z46rqbBAbA5eMoGQ
- whwC8rbAabiGdoMdmR1hlMnFSM8tarCOQHn/RGneVSBVW4DEM/sYyIchVHWgzgTH
- IZTHIy9j8Ho=
- =6Dq1
- -----END PGP SIGNATURE-----
-